# coding=utf8
import sys
from typing import Iterable

sys.path.append('../')
from pyjvm.classpath import Classpath
from pyjvm.exceptions import MainMethodNotFoundError
from pyjvm.instructions.common import ClassInitializer
from pyjvm.interpreter import interpret
from pyjvm.runtime.heap import Heap
from pyjvm.runtime.loader import ClassLoader
from pyjvm.runtime.strpool import StringPool
from pyjvm.runtime.thread import Thread, Frame


class PyJvm(object):

    def __init__(self, cnf):
        self.cp = Classpath(cnf.jre, cnf.classpath)
        self.class_loader = ClassLoader(self.cp)
        self.main_thread = Thread()
        self.__initialized = False

    def initialize(self):
        print('PyJvm initializing....')
        __import__('pyjvm.native')  # 注册本地方法 (import pyjvm.native 会被idea标未使用）
        vm_class = self.class_loader.load_class('sun/misc/VM')
        ClassInitializer.init_class(self.main_thread, vm_class)
        interpret(self.main_thread, False)
        print('PyJvm initialized! ')
        self.__initialized = True

    def exec_main(self, main_class: str, args: Iterable[str] = []):
        if not self.__initialized:
            self.initialize()
        print('PyJvm Process : execute %s.main .....' % main_class)
        print()
        class_name = main_class.replace('.', '/')
        main_class = self.class_loader.load_class(class_name)

        main_method = main_class.get_main_method()
        if main_method is None:
            raise MainMethodNotFoundError('没有找到main方法！')

        args_arr_ref = self.__get_j_main_args(args)
        frame: Frame = self.main_thread.new_frame(main_method)
        frame.local_vars[0] = args_arr_ref
        self.main_thread.push_frame(frame)
        interpret(self.main_thread, False)
        print()
        print('PyJvm Process finished! ')

    def __get_j_main_args(self, args: Iterable[str]):
        string_class = self.class_loader.load_class('java/lang/String')
        string_array_class = string_class.get_component_array_class()
        j_main_args = Heap.new_from_data(string_array_class,
                                         [StringPool.new(self.class_loader, arg)
                                          for arg in args])
        return j_main_args


def start():
    main_class = sys.argv[1]
    args = sys.argv[2:]
    import pyjvm.vmcnf
    PyJvm(pyjvm.vmcnf).exec_main(main_class, args)


__all__ = ['PyJvm']

if __name__ == '__main__':
    start()
